'''
   Created on Jul 30, 2011
   
   @author: Krystian Brachmanski
'''
   
import logging
import fileParsers
import gnuplotGenerator
   
class yapcgSarGenerator(object):
    '''
    Class for generating the sar charts
    
    @author: Krystian Brachmanski
    @requires: logging, fileParsers, gnuplotGenerator    
    '''
   
    log = logging.getLogger('yapcg.yapcgSarGenerator')
   
    def __init__(self, dirHandler):
        '''
        Constructor
        '''
        self.dirHandler = dirHandler
        self.sarMemList = [ ]
        self.sarCpuList = [ ]
    
    def generateSarCpuStats(self, sarCpuParser,datafile,gpFile, epsFile,keys=None):
        '''
        Function used to generate the charts for CPU statistics
        
        @param sarCpuParser: parser for sar cpu statistics
        @param datafile: the datafile that will be passed as a parameter to SarCpyGnuplotGenerator object
        @param gpFile: the name of the gnuplot file
        @param epsFile: the name of the output chart file
        @param keys: the list of keys to be displayed as series on chart     
        '''
        if keys == None:
            sargnuPlot = gnuplotGenerator.SarCpuGnuplotGenerator(sarCpuParser.columns)
        else:
            sargnuPlot = gnuplotGenerator.SarCpuGnuplotGenerator(sarCpuParser.columns,keys)
        sargnuPlot.generateGnuplotFile(gpFile, datafile, epsFile)
   
    def generateSarMemStats(self, sarMemParser, datafile,gpFile, epsFile,keys=None,ylabel=None):
        '''
        Function used to generate the charts for memory statistics
        
        @param sarMemParser: parser for sar cpu statistics
        @param datafile: the datafile that will be passed as a parameter to SarMemGnuplotGenerator object
        @param gpFile: the name of the gnuplot file
        @param epsFile: the name of the output chart file
        @param keys: the list of keys to be displayed as series on chart     
        @param ylabel : the title to be displayed next to the ylable
        '''
        sargnuPlot = gnuplotGenerator.SarMemGnuplotGenerator(sarMemParser.columns,keys)
        if (ylabel != None):
            sargnuPlot.ylabel = ylabel
        sargnuPlot.generateGnuplotFile(gpFile, datafile, self.dirHandler.reportDir + epsFile)
        self.sarMemList.append(epsFile)
   
    def generateMemStats(self, gpFile, datafile, sarMemParser, keys, ylabel = None):
        '''
        Function used to generate the charts for memory statistics and append the filen
        
        @param sarMemParser: parser for sar cpu statistics
        @param datafile: the datafile that will be passed as a parameter to SarCpyGnuplotGenerator object
        @param gpFile: the name of the gnuplot file for which the directory and suffix shall be appended (used for output chart file as well)
        @param keys: the list of keys to be displayed as series on chart     
        @param ylabel : the title to be displayed next to the ylable
        '''
        sarMemEpsFile = self.dirHandler.getMemChartFilepath(gpFile + ".eps")
        gpsMemFile = self.dirHandler.getDirectoryForGnuplotFile(gpFile + ".gp")
        self.generateSarMemStats(sarMemParser, datafile,gpsMemFile, sarMemEpsFile, keys, ylabel)
   
    def parseSarMemFile(self, inSarMemFile):
        '''
        Function used to parse the input sar file containing the memory statistics and produce the output file
        
        @param inSarMemFile: the path to the input sar file
        '''
        file = self.dirHandler.getDataFileName("parsedSarMemFile.data")
        sarMemParser = fileParsers.SarMemParser()
        sarMemParser.parseFile(inSarMemFile, file)
        self.generateMemStats("sarMemGnuPlot",file,sarMemParser,[sarMemParser.keys[0]]) 
        self.generateMemStats("sarMemGnuPlot1",file,sarMemParser,sarMemParser.keys[1:], "Size [kB]") 
   
    def parseSarCpuFile(self, inSarCpuFile):
        '''
        Function used to parse the input sar file containing the CPU statistics and produce the output file
        
        @param inSarCpuFile: the path to the input sar file
        '''
        file = self.dirHandler.getDataFileName("parsedSarCpuFile.dat")
        gpsFile = self.dirHandler.getDirectoryForGnuplotFile("tmpSarGnuPlot.gp")
        gpsFile2 = self.dirHandler.getDirectoryForGnuplotFile("tmpSarGnuPlotUsrSysIo.gp")
    
        self.log.info("Parsing Sar CPU file: " + inSarCpuFile)
        sarCpuParser = fileParsers.SarCpuParser()
        sarCpuParser.parseFile(inSarCpuFile, file)
        self.stats = sarCpuParser.getStatistics()
        for i in self.stats.keys():
            self.log.info("Stats for " + i + " = " +str(self.stats[i].min) + "," + str('{0:g}'.format(self.stats[i].avg())) + "," + str(self.stats[i].q95()) + "," + str(self.stats[i].max))

        sarCpuEpsFile = self.dirHandler.getCpuChartFilepath("outDataFile.eps")
        sarCpuEpsFile2 = self.dirHandler.getCpuChartFilepath("outDataFileUsrSys.eps")
        self.generateSarCpuStats(sarCpuParser,file,gpsFile, self.dirHandler.reportDir + sarCpuEpsFile)
        self.generateSarCpuStats(sarCpuParser,file,gpsFile2, self.dirHandler.reportDir + sarCpuEpsFile2, [ "user", "system", "iowait" ])
        self.sarCpuList.append(sarCpuEpsFile)
        self.sarCpuList.append(sarCpuEpsFile2)
                
class yapcgPidstatGenerator(object):
    '''
    Class for generating the pidstat charts
    
    @author: Krystian Brachmanski
    @requires: logging, fileParsers, gnuplotGenerator    
    '''
   
    log = logging.getLogger('yapcg.yapcgPidstatGenerator')

    def __init__(self, dirHandler):
        self.dirHandler = dirHandler
        self.filemap = { }
        self.heap_cpu = []
        self.heap_mem = []
        self.cpuThresholdList = []
        self.memThresholdList = []
        self.generalSectionFigure = []
        self.detailCpuSectionFigure = []
        self.detailMemSectionFigure = []
        self.detailIoSectionFigure = []
        
    def getDescriptionForName(self, name):
        '''
        @param name: the name for which the descrption shall be returned 
        @return: description of the series
        '''
        return name.replace("_"," ")
    
    def getNiceSectionName(self, title):
        '''
        @param title: the name for which the nice title shall be returned 
        @return: pid beautified form
        '''
        list = title.replace("_"," ").replace(":"," ").split(" ")
        # First element pid
        pid = list.pop(0)    
        
        tmp = ""
        i = 0
        for elem in list:
            if i > 0:
                tmp += "\\_"
            tmp += elem 
            i += 1
        tmp += "(pid=" + pid + ")" 
        return tmp 
    
    def writeGlobalMemGnuplotFile(self, format,showNoise):
        '''
        Used to generate memory gnuplot file for generating global statistics (top processes with or without noise)
        @param format: format of the output chart
        @param showNoise: if True display only the top processes, if False show also other processes          
        '''
        sarMemParser = gnuplotGenerator.pidGlobalGenerator("Memory statistics", showNoise, format, self.dirHandler)
        gpFile = self.dirHandler.getDirectoryForGnuplotFile("memMainStatistics.gp")
        out = self.dirHandler.getMemChartFilepath("memStats.eps")
        sarMemParser.writeGnuPlotFile(self.heap_mem, self.filemap,["12"], self.dirHandler.reportDir + out, gpFile)
        return out
    
    def writeGlobalCpuGnuplotFile(self, format,showNoise):
        '''
        Used to generate CPU gnuplot file for generating global statistics (top processes with or without noise)
        @param format: format of the output chart
        @param showNoise: if True display only the top processes, if False show also other processes          
        '''
        pidCpuGenerator = gnuplotGenerator.pidGlobalGenerator("Cpu utilization", showNoise, format, self.dirHandler)
        gpFile = self.dirHandler.getDirectoryForGnuplotFile("cpuMainStatistics.gp")
        out = self.dirHandler.getCpuChartFilepath("cpuStats.eps")
        pidCpuGenerator.writeGnuPlotFile(self.heap_cpu, self.filemap,["6"], self.dirHandler.reportDir + out, gpFile)
        return out
    
    def writePerProcessCpuGnuplotFile(self, name,format):
        '''
        Used to generate CPU gnuplot file for generating per process statistics
        @param name: the name of the process for which the statistic is to be generated 
        @param format: format of the output chart
        @return: the name of the generated file          
        '''
        pidCpuGenerator = gnuplotGenerator.pidPerProcessCpuGenerator(format)
        gpFile = self.dirHandler.getDirectoryForGnuplotFile("cpu" + name + ".gp")
        out = self.dirHandler.getCpuChartFilepath("cpu" + name.replace(".","_").replace(":","_") + ".eps")
        pidCpuGenerator.writeGnuPlotFile(name, self.dirHandler.reportDir + out,gpFile,self.dirHandler.getDataFileName(name))
        return out
    
    def writePerProcessMemGnuplotFile(self, name,format):
        '''
        Used to generate memory gnuplot file for generating per process statistics
        @param name: the name of the process for which the statistic is to be generated 
        @param format: format of the output chart
        @return: the name of the generated file          
        '''
        pidMemGenerator = gnuplotGenerator.pidPerProcessMemGenerator(format)
        gpFile = self.dirHandler.getDirectoryForGnuplotFile("mem" + name + ".gp")
        out = self.dirHandler.getMemChartFilepath("mem" + name.replace(".","_").replace(":","_") + ".eps")
        pidMemGenerator.writeGnuPlotFile(name, self.dirHandler.reportDir + out,gpFile,self.dirHandler.getDataFileName(name))
        return out

    def writePerProcessIoGnuplotFile(self, name,format):
        '''
        Used to generate memory gnuplot file for generating per process statistics
        @param name: the name of the process for which the statistic is to be generated 
        @param format: format of the output chart
        @return: the name of the generated file          
        '''
        pidIoGenerator = gnuplotGenerator.pidPerProcessIoGenerator(format)
        gpFile = self.dirHandler.getDirectoryForGnuplotFile("io" + name + ".gp")
        out = self.dirHandler.getIoChartFilepath("io" + name.replace(".","_").replace(":","_") + ".eps")
        pidIoGenerator.writeGnuPlotFile(name, self.dirHandler.reportDir + out,gpFile,self.dirHandler.getDataFileName(name))
        return out
    
    def writeGnuplotControlFiles(self, format = "eps", showNoise = True):
        '''
        Used to generate gnuplot files for CPU and memory
        @param format: format of the output chart
        @param showNoise: display or not least relevant processes on charts 
        '''    
        self.log.info("Generating per process CPU charts")
        for key in self.filemap:             
            self.detailCpuSectionFigure.append((self.getNiceSectionName(key),self.writePerProcessCpuGnuplotFile(key,format)))

        self.log.info("Generating summary CPU chart")
        self.generalSectionFigure.append(self.writeGlobalCpuGnuplotFile(format,showNoise))
    
        self.log.info("Generating per process memory charts")
        for key in self.filemap: 
            self.detailMemSectionFigure.append((self.getNiceSectionName(key),self.writePerProcessMemGnuplotFile(key,format)))
        self.log.info("Generating summary memory chart")
        self.generalSectionFigure.append(self.writeGlobalMemGnuplotFile(format,showNoise))    

    def writeGnuplotIOControlFiles(self, format = "eps", showNoise = True):        
        '''
        Used to generate gnuplot files for IO
        @param format: format of the output chart
        @param showNoise: display or not least relevant processes on charts 
        '''    

        self.log.info("Generating per process IO charts")
        for key in self.filemap: 
            self.detailIoSectionFigure.append((self.getNiceSectionName(key),self.writePerProcessIoGnuplotFile(key,format)))

        self.log.info("Generating summary IO chart")
        ioGnuplotGenerator = gnuplotGenerator.pidstatIoGenerator(self.dirHandler)
        gpFile = self.dirHandler.getDirectoryForGnuplotFile("ioFile.gp")
        outFile = self.dirHandler.getIoChartFilepath("ioStats.eps")
        ioGnuplotGenerator.writeGnuPlotFile(self.dirHandler.reportDir + outFile,gpFile, self.pidParser.ioTopRdProcessList.getProcessList(), self.filemap)
        self.generalSectionFigure.append(outFile)    
        
    def parsePidstatFile(self, inputFile, procNum, processBlackList):
        '''
        Main method for parsing the pidstat file
        @param inputFile: the name of the input file to be parsed
        @param procNum: the number of top processes to be displayed on legend
        @param processBlackList: the list of ignored processes which will not be displayed on charts and only overall statistics will be collected
        '''    

        self.log.info("Loading input data from : " + inputFile)
        pidFile = self.dirHandler.getDataFileName("parsedPidFile.dat")
        self.pidParser = fileParsers.PidStatParser(procNum, processBlackList.split(','), self.dirHandler)
        self.pidParser.parseFile(inputFile, pidFile)

        self.heap_cpu = self.pidParser.getTopCpuProcessList()
        self.heap_mem = self.pidParser.getTopMemProcessList()
        self.filemap = self.pidParser.getFileMap()

        #Generating files for GnuPlot
        self.writeGnuplotControlFiles()
        self.writeGnuplotIOControlFiles(self.pidParser, self.filemap)
